package com.ym.domain.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ym.domain.common.base.MedisValue;
import com.ym.domain.common.util.DateComUtil;
import com.ym.domain.common.util.SnowflakeIdWorker;
import com.ym.domain.dao.MedisService;
import com.ym.domain.model.Medis;
import com.ym.domain.service.MedisBizService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class MedisBizServiceImpl implements MedisBizService {

    @Autowired
    private MedisService mydisService;

    @Override
    public boolean put(String key, String value) {
        if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) return false;
        if (checkMydisLength(key, value)) return false;

        Medis mydis = getMydisByKey(key);
        if (null != mydis) {
            mydis.setCacheValue(value);
            mydis.setExpireTime(0L);
        } else {
            LocalDateTime localDateTimeNow = DateComUtil.getLocalDateTimeNow();
            mydis = new Medis(SnowflakeIdWorker.nextId(), key, value, localDateTimeNow, localDateTimeNow, 0L);
        }
        return mydisService.saveOrUpdate(mydis);
    }

    private Medis getMydisByKey(String key) {
        QueryWrapper<Medis> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Medis::getCacheKey, key);
        return mydisService.getOne(queryWrapper);
    }

    @Override
    public boolean put(String key, String value, Long expireTime) {
        if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) return false;
        if (checkMydisLength(key, value)) return false;

        Medis mydis = getMydisByKey(key);
        if (null != mydis) {
            mydis.setCacheValue(value);
            mydis.setExpireTime(expireTime);
        } else {
            LocalDateTime localDateTimeNow = DateComUtil.getLocalDateTimeNow();
            mydis = new Medis(SnowflakeIdWorker.nextId(), key, value, localDateTimeNow, localDateTimeNow, expireTime);
        }
        return mydisService.saveOrUpdate(mydis);
    }

    @Override
    public MedisValue get(String key) {
        if (StringUtils.isBlank(key)) return new MedisValue(false, null);
        Medis mydis = getMydisByKey(key);
        if (null == mydis) return new MedisValue(false, null);

        Long expireTime = mydis.getExpireTime();
        if (expireTime == null || expireTime == 0) {
            return new MedisValue(false, mydis.getCacheValue());
        }

        LocalDateTime createTime = mydis.getCreateTime();
        if (DateComUtil.getLocalDateTimeNow().isAfter(createTime.plusSeconds(mydis.getExpireTime()))) {
            return new MedisValue(true, null);
        }

        return new MedisValue(false, mydis.getCacheValue());
    }

    @Override
    public Medis getMedis(String key) {
        if (StringUtils.isBlank(key)) return null;
        return getMydisByKey(key);
    }

    @Override
    public boolean remove(String key) {
        if (StringUtils.isBlank(key)) return false;

        Medis mydis = getMydisByKey(key);
        if (null == mydis) return true;

        mydisService.deleteRealById(mydis.getId());

        return true;
    }

    @Override
    public boolean isExpired(String key) {
        if (StringUtils.isBlank(key)) return true;
        return isExpired(getMydisByKey(key));
    }

    private boolean isExpired(Medis mydis) {
        if (null == mydis) return true;
        Long expireTime = mydis.getExpireTime();
        if (expireTime == null || expireTime == 0) {
            return false;
        }
        return DateComUtil.getLocalDateTimeNow().isAfter(mydis.getCreateTime().plusSeconds(mydis.getExpireTime()));
    }

    @Override
    public void clearExpiredKey() {
        log.info("【清除Medis过期数据】clearExpiredKey start");
        List<Medis> mydisList = mydisService.getExpiredKey();
        if (CollectionUtils.isNotEmpty(mydisList)) {
            mydisList.forEach(mydis -> mydisService.deleteRealMydis(mydis));
        }
    }

    private boolean checkMydisLength(String key, String value) {
        return key.length() >= 245 || value.length() >= 2540;
    }

}
